package org.springblade.modules.notice.aspect;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.notice.annotation.MsgNotice;
import org.springblade.modules.notice.core.Process;
import org.springblade.modules.notice.dto.NoticeTaskParam;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 消息通知切面
 * @Author ysq
 * @Date 2024/11/14
 **/
@Aspect
@Component
@Slf4j
public class MsgNoticeAspect {
	@Resource
	private Process process;

	@Pointcut("@annotation(org.springblade.modules.notice.annotation.MsgNotice)")
    public void msgNotice() {
    }

	/**
	 * 后置通知
	 * @param joinPoint
	 */
	@AfterReturning(value = "msgNotice()", returning = "result")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		// 获取方法签名
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		// 获取方法对象
		Method method = signature.getMethod();
		MsgNotice msgNotice = method.getAnnotation(MsgNotice.class);
		// 获取方法参数
		Object[] args = joinPoint.getArgs();
		Parameter[] parameters = method.getParameters();

		// 处理参数映射
		Map<String, Object> params;
		if (msgNotice.parameterSource() == 0) {
			params = paramResolver(parameters, args);
		}  else {
			params = returningResolver(result, msgNotice.parameterName());
		}
		if (params == null) {
			log.error("消息通知切面#MsgNoticeAspect fail:{},businessType:{},triggerNode:{}",
				"参数解析失败", msgNotice.businessType().getDesc(), msgNotice.node().getCode());
			return;
		}

		Object target = null;
		String[] names = msgNotice.parameterName().split("\\.");
		if (names.length == 1) {
			target =  params.get(msgNotice.parameterName());
		} else {
			Object value = params.get(names[0]);
			String jsonString = JSON.toJSONString(value);
			JSONObject jsonObject = JSON.parseObject(jsonString);
			for (int i = 1; i < names.length; i++) {
				if (i == names.length - 1) {
					target =  jsonObject.get(names[i]);
				} else {
					jsonObject = jsonObject.getJSONObject(names[i]);
				}
			}
		}
		if (target == null) {
			log.error("消息通知切面#MsgNoticeAspect fail:{},businessType:{},triggerNode:{}",
				"参数解析失败", msgNotice.businessType().getDesc(), msgNotice.node().getCode());
			return;
		}

		NoticeTaskParam noticeTaskParam = NoticeTaskParam.builder()
			.businessType(msgNotice.businessType().getCode())
			.triggerNode(msgNotice.node().getCode())
			.bizId((Long) target)
			.tenantId(AuthUtil.getTenantId())
			.build();
		process.noticeBusinessProcess(noticeTaskParam);
	}

	/**
	 * 入参解析
	 * @param parameters
	 * @param args
	 * @return
	 */
	private Map<String, Object> paramResolver(Parameter[] parameters, Object[] args) {
		Map<String, Object> params = new HashMap<>();
		for (int i = 0; i < parameters.length; i++) {
			Parameter parameter = parameters[i];
			Object value = args[i];
			// 动态获取参数类型
			Class<?> paramType = parameter.getType();
			if (isBasicType(paramType)) {
				// 处理基础类型
				params.put(parameter.getName(), value);
			} else if (Map.class.isAssignableFrom(paramType)) {
				// 处理 Map 类型参数
				Map<?, ?> map = (Map<?, ?>) value;
				map.forEach((k, v) -> params.put(k.toString(), v));
			} else {
				params.put(parameter.getName(), value);
			}
		}
		return params;
	}

	/**
	 * 返回值解析
	 * @param result
	 * @param parameterName
	 * @return
	 */
	private Map<String, Object> returningResolver(Object result, String parameterName) {
		Map<String, Object> params = new HashMap<>();
		Class<?> paramType = result.getClass();
		Object value = result;
		if (isBasicType(paramType)) {
			// 处理基础类型
			params.put(parameterName, value);
		} else if (Map.class.isAssignableFrom(paramType)) {
			// 处理 Map 类型参数
			Map<?, ?> map = (Map<?, ?>) value;
			map.forEach((k, v) -> params.put(k.toString(), v));
		} else {
			params.put("result", value);
		}
		return params;
	}

	/**
	 * 判断是否是基本类型或其对应的包装类型
	 * @param paramType
	 * @return
	 */
	public static boolean isBasicType(Class<?> paramType) {
		// 检查是否是基本类型
		if (paramType.isPrimitive()) {
			return true;
		}

		// 检查是否是基本类型的包装类型
		return paramType.equals(Integer.class) || paramType.equals(Long.class) ||
			paramType.equals(Boolean.class) || paramType.equals(String.class) ||
			paramType.equals(Double.class) || paramType.equals(Float.class) ||
			paramType.equals(Character.class) || paramType.equals(Byte.class) ||
			paramType.equals(Short.class);
	}

}
